package com.listeningframework.boot.autoconfigure.security.authentication;

import com.google.common.collect.Lists;
import com.listeningframework.boot.autoconfigure.security.overrides.RandomAuthenticationException;
import com.listeningframework.boot.autoconfigure.security.userdetails.SecurityMenus;
import com.listeningframework.boot.autoconfigure.security.userdetails.SecurityMenusAccordion;
import com.listeningframework.boot.autoconfigure.security.userdetails.SecurityMenusAccordionTree;
import com.listeningframework.boot.autoconfigure.security.userdetails.SecurityUserDetails;
import com.listeningframework.boot.commons.string.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;

import javax.security.auth.login.CredentialExpiredException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author listening
 * @version $Id: SpringSecurityUtils.java, v 0.1 2015年7月18日 下午8:38:32 listening Exp $
 */
public class SpringSecurityUtils {
    /**
     * 认证信息
     *
     * @return Authentication
     */
    public static Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * Get Current Login User
     *
     * @return String
     */
    public static String getCurrentUser() {
        Authentication authentication = getAuthentication();
        if (authentication == null) {
            return null;
        }
        Object principal = authentication.getPrincipal();
        if (principal == null) {
            return null;
        }
        String username = principal.toString();
        if (principal instanceof UserDetails) {
            username = ((UserDetails) principal).getUsername();
        }
        return username;
    }

    /**
     * 用户登录信息
     *
     * @return SecurityUserDetails
     */
    public static SecurityUserDetails getUserDetails() {
        Authentication authentication = getAuthentication();
        if (authentication == null) {
            return null;
        }
        Object principal = authentication.getPrincipal();
        if (!(principal instanceof SecurityUserDetails)) {
            return null;
        }
        return (SecurityUserDetails) authentication.getPrincipal();
    }

    /**
     * 是否拥有权限
     *
     * @param permission 权限名称
     * @return boolean
     */
    public static boolean hasPermission(String permission) {
        Authentication authentication = getAuthentication();
        if (authentication == null) {
            return false;
        }
        Object principal = authentication.getPrincipal();
        if (principal == null) {
            return false;
        }
        Collection<? extends GrantedAuthority> authList = null;
        if (principal instanceof UserDetails) {
            authList = ((UserDetails) principal).getAuthorities();
        }
        if (authList == null || authList.isEmpty()) {
            return false;
        }
        return authList.contains(new SimpleGrantedAuthority(permission));
    }

    /**
     * 是否已经认证
     *
     * @return boolean
     */
    public static boolean isAuthenticated() {
        return isLogin();
    }

    /**
     * Check Is The Current user
     *
     * @param username 用户名
     * @return boolean
     */
    public static boolean isCurrentUser(String username) {
        return com.listeningframework.boot.commons.string.StringUtils.equals(getCurrentUser(), username);
    }

    /**
     * 是否RBAC
     *
     * @return boolean
     */
    public static boolean isRBACAdmin() {
        SecurityUserDetails details = getUserDetails();
        return StringUtils.equalsIgnoreCase(details == null ? "" : details.getUserId(), "ROLE_RBAC");
    }

    /**
     * Check Is Login
     *
     * @return boolean
     */
    public static boolean isLogin() {
        String currentUser = getCurrentUser();
        return StringUtils.isNotBlank(currentUser) && !isAnonymous();
    }

    /**
     * Check Is Anonymous Login
     *
     * @return boolean
     */
    public static boolean isAnonymous() {
        return StringUtils.equalsIgnoreCase(getCurrentUser(), "anonymousUser");
    }

    /**
     * Get Login Exception
     *
     * @param request HttpServletRequest
     * @return String
     */
    public static String getLastExceptionMsg(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Assert.notNull(session, "session can not be null");
        Exception exception = (Exception) session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
        if (exception == null) {
            return null;
        }
        String message = "登录异常";
        String exceptionMsg = exception.getClass().getName();
        if (StringUtils.equalsIgnoreCase(exceptionMsg, RandomAuthenticationException.class.getName())) {
            message = "验证码输入有误";
        }
        if (StringUtils.equalsIgnoreCase(exceptionMsg, UsernameNotFoundException.class.getName())) {
            message = "用户信息不存在, 您暂时无法登录";
        }
        if (StringUtils.equalsIgnoreCase(exceptionMsg, LockedException.class.getName())) {
            message = "用户被锁定, 您暂时无法登录";
        }
        if (StringUtils.equalsIgnoreCase(exceptionMsg, DisabledException.class.getName())) {
            message = "用户不可用, 您暂时无法登录";
        }
        if (StringUtils.equalsIgnoreCase(exceptionMsg, CredentialExpiredException.class.getName())) {
            message = "用户密码已过期, 您暂时无法登录";
        }
        if (StringUtils.equalsIgnoreCase(exceptionMsg, BadCredentialsException.class.getName())) {
            message = "用户名或密码输入有误,请核对您的输入！";
        }
        return message;
    }

    /**
     * 所有菜单
     *
     * @return List
     */
    public static List<SecurityMenusAccordionTree> getAllSecurityTreeMenus() {
        List<SecurityMenusAccordionTree> resultList = Lists.newArrayList();
        Object principal = SpringSecurityUtils.getAuthentication().getPrincipal();
        if (principal == null || !(principal instanceof SecurityUserDetails)) {
            return resultList;
        }
        SecurityUserDetails details = (SecurityUserDetails) principal;
        SecurityMenus securityMenus = details.getSecurityMenus();
        List<SecurityMenusAccordion> accordionList = securityMenus.getSecurityAccordionList();
        Map<String, List<SecurityMenusAccordionTree>> menuMap = securityMenus.getAccordionTreeListMap();
        if (!CollectionUtils.isEmpty(accordionList)) {
            for (SecurityMenusAccordion accordion : accordionList) {
                SecurityMenusAccordionTree accordionMenu = new SecurityMenusAccordionTree();
                accordionMenu.setId(accordion.getId());
                accordionMenu.setText(accordion.getText());
                if (menuMap == null || !menuMap.containsKey(accordion.getId())) {
                    resultList.add(accordionMenu);
                    continue;
                }
                accordionMenu.setChildren(menuMap.get(accordion.getId()));
                resultList.add(accordionMenu);
            }
        }
        return resultList;
    }


    /**
     * 所有手风琴菜单
     *
     * @return List
     */
    public static List<SecurityMenusAccordion> getAccordions() {
        List<SecurityMenusAccordion> accordions = Lists.newArrayList();
        Object principal = SpringSecurityUtils.getAuthentication().getPrincipal();
        if (principal == null || !(principal instanceof SecurityUserDetails)) {
            return accordions;
        }
        SecurityMenus securityMenus = ((SecurityUserDetails) principal).getSecurityMenus();
        if (securityMenus != null && securityMenus.getSecurityAccordionList() != null) {
            accordions.addAll(securityMenus.getSecurityAccordionList());
        }
        return accordions;
    }

    /**
     * 手风琴子树
     *
     * @param accordionId 琴键ID
     * @return List
     */
    public static List<SecurityMenusAccordionTree> getAccordionTrees(String accordionId) {
        List<SecurityMenusAccordionTree> accordionTrees = Lists.newArrayList();
        Object principal = SpringSecurityUtils.getAuthentication().getPrincipal();
        if (principal == null || !(principal instanceof SecurityUserDetails)) {
            return accordionTrees;
        }
        SecurityMenus securityMenus = ((SecurityUserDetails) principal).getSecurityMenus();
        if (securityMenus == null) {
            return accordionTrees;
        }
        Map<String, List<SecurityMenusAccordionTree>> treeMenuMap = securityMenus.getAccordionTreeListMap();
        if (treeMenuMap == null || treeMenuMap.isEmpty() || !treeMenuMap.containsKey(accordionId)) {
            return accordionTrees;
        }
        accordionTrees.addAll(treeMenuMap.get(accordionId));
        return accordionTrees;
    }
}
